use std::{
    fs::File,
    io::{Read, Seek, SeekFrom},
    path::Path,
};

use anyhow::{Context, Result, anyhow};
use serde::Serialize;
use utoipa::ToSchema;

use crate::{
    audio_data_converter, single_station_data_matrix::SingleStationDataMatrix,
    station_data_matrix::StationDataMatrix,
};

/// 所有通道数据
#[derive(Debug, Serialize, ToSchema)]
pub struct SoundWaveAllChannels {
    pub channels: usize,
    pub samples: usize,
    pub data: Vec<Vec<f32>>,
}

/// 单通道数据
#[derive(Debug, Serialize, ToSchema)]
pub struct SoundWaveSingleChannel {
    pub channel_index: usize,
    pub samples: usize,
    pub data: Vec<f32>,
}

/// 声波读取服务（Rust 版本）
pub struct SoundWaveReaderService;

impl SoundWaveReaderService {
    pub fn new() -> Self {
        Self
    }

    /// 读取所有通道的数据，返回二维数组
    #[allow(clippy::too_many_arguments)]
    pub fn read_sound_wave_all_channels_data(
        &self,
        file_path: &Path,
        smprate: u32,
        channels: usize,
        depth: u32,
        symbol_type: &str,
        offset: f64,
        duration: f64,
        coef: f32,
        range: f32,
        is_convert_to_vol: bool,
    ) -> Result<SoundWaveAllChannels> {
        let (buffer, actual_samples, bytes_per_sample) =
            self.read_raw_window(file_path, smprate, channels, depth, offset, duration)?;

        let mut data = vec![Vec::with_capacity(actual_samples); channels];

        for i in 0..actual_samples {
            let base = i * channels * bytes_per_sample;
            for channel in 0..channels {
                let position = base + channel * bytes_per_sample;
                let mut sample =
                    audio_data_converter::convert_to_sample(&buffer, position, symbol_type, depth)?;

                if is_convert_to_vol {
                    sample = convert_to_voltage(sample, coef, range);
                }

                data[channel].push(sample);
            }
        }

        Ok(SoundWaveAllChannels {
            channels,
            samples: actual_samples,
            data,
        })
    }

    /// 读取单通道数据，返回 Vec<f32>
    #[allow(clippy::too_many_arguments)]
    pub fn read_sound_wave_data_by_channel(
        &self,
        file_path: &Path,
        smprate: u32,
        channels: usize,
        depth: u32,
        symbol_type: &str,
        offset: f64,
        duration: f64,
        channel_index: usize,
        coef: f32,
        range: f32,
        is_convert_to_vol: bool,
    ) -> Result<SoundWaveSingleChannel> {
        if channel_index == 0 || channel_index > channels {
            return Err(anyhow!(
                "无效的通道索引: {}（总通道数 {}）",
                channel_index,
                channels
            ));
        }

        let (buffer, actual_samples, bytes_per_sample) =
            self.read_raw_window(file_path, smprate, channels, depth, offset, duration)?;

        let channel_offset = channel_index - 1;
        let mut data = Vec::with_capacity(actual_samples);

        for i in 0..actual_samples {
            let base = i * channels * bytes_per_sample;
            let position = base + channel_offset * bytes_per_sample;
            let mut sample =
                audio_data_converter::convert_to_sample(&buffer, position, symbol_type, depth)?;

            if is_convert_to_vol {
                sample = convert_to_voltage(sample, coef, range);
            }

            data.push(sample);
        }

        Ok(SoundWaveSingleChannel {
            channel_index,
            samples: actual_samples,
            data,
        })
    }

    /// 将读取到的所有通道数据写入单测站矩阵
    #[allow(clippy::too_many_arguments)]
    pub fn read_sound_wave_all_channels_directly_to_single_station_matrix(
        &self,
        matrix: &mut SingleStationDataMatrix,
        start_sample_index: usize,
        max_samples_to_fill: usize,
        file_path: &Path,
        smprate: u32,
        channels: usize,
        depth: u32,
        symbol_type: &str,
        offset: f64,
        duration: f64,
        coef: f32,
        range: f32,
        is_convert_to_vol: bool,
    ) -> Result<usize> {
        let result = self.read_sound_wave_all_channels_data(
            file_path,
            smprate,
            channels,
            depth,
            symbol_type,
            offset,
            duration,
            coef,
            range,
            is_convert_to_vol,
        )?;

        let samples_to_write = result
            .samples
            .min(max_samples_to_fill)
            .min(matrix.max_sample_count());

        for channel in 0..channels.min(matrix.channel_count()) {
            for (idx, value) in result.data[channel]
                .iter()
                .take(samples_to_write)
                .enumerate()
            {
                matrix.write_sample(channel, start_sample_index + idx, *value)?;
            }
        }

        Ok(samples_to_write)
    }

    /// 将指定通道数据写入测站矩阵
    #[allow(clippy::too_many_arguments)]
    pub fn read_sound_wave_directly_to_matrix(
        &self,
        matrix: &mut StationDataMatrix,
        station_index: usize,
        start_column_index: usize,
        max_columns_to_fill: usize,
        file_path: &Path,
        smprate: u32,
        channels: usize,
        depth: u32,
        symbol_type: &str,
        offset: f64,
        duration: f64,
        channel_index: usize,
        coef: f32,
        range: f32,
        is_convert_to_vol: bool,
    ) -> Result<usize> {
        let result = self.read_sound_wave_data_by_channel(
            file_path,
            smprate,
            channels,
            depth,
            symbol_type,
            offset,
            duration,
            channel_index,
            coef,
            range,
            is_convert_to_vol,
        )?;

        let samples_to_write = result
            .samples
            .min(max_columns_to_fill)
            .min(matrix.max_sample_count().saturating_sub(start_column_index));

        for (idx, value) in result.data.iter().take(samples_to_write).enumerate() {
            matrix.write_sample(station_index, start_column_index + idx, *value)?;
        }

        Ok(samples_to_write)
    }

    /// 简单版本的 MMF 读取，直接复用普通逻辑
    #[allow(clippy::too_many_arguments)]
    pub fn read_sound_wave_directly_to_matrix_mmf(
        &self,
        matrix: &mut StationDataMatrix,
        station_index: usize,
        start_column_index: usize,
        max_columns_to_fill: usize,
        file_path: &Path,
        smprate: u32,
        channels: usize,
        depth: u32,
        symbol_type: &str,
        offset: f64,
        duration: f64,
        channel_index: usize,
        coef: f32,
        range: f32,
        is_convert_to_vol: bool,
    ) -> Result<usize> {
        self.read_sound_wave_directly_to_matrix(
            matrix,
            station_index,
            start_column_index,
            max_columns_to_fill,
            file_path,
            smprate,
            channels,
            depth,
            symbol_type,
            offset,
            duration,
            channel_index,
            coef,
            range,
            is_convert_to_vol,
        )
    }

    /// 读取指定窗口的原始字节数据，并返回 (buffer, actual_samples, bytes_per_sample)
    fn read_raw_window(
        &self,
        file_path: &Path,
        smprate: u32,
        channels: usize,
        depth: u32,
        offset: f64,
        duration: f64,
    ) -> Result<(Vec<u8>, usize, usize)> {
        if channels == 0 {
            return Err(anyhow!("通道数必须大于 0"));
        }
        if depth % 8 != 0 {
            return Err(anyhow!("位深必须是 8 的倍数: {}", depth));
        }

        let bytes_per_sample = (depth / 8) as usize;
        let step = bytes_per_sample * channels;

        let samples_to_read = (duration * smprate as f64) as usize;
        if samples_to_read == 0 {
            return Ok((Vec::new(), 0, bytes_per_sample));
        }

        let mut file = File::open(file_path)
            .with_context(|| format!("打开文件失败: {}", file_path.display()))?;

        let file_len = file
            .metadata()
            .map(|m| m.len())
            .with_context(|| format!("获取文件大小失败: {}", file_path.display()))?;

        let start_sample = ((offset * smprate as f64) as i64).max(0) as u64;
        let start_position = start_sample * step as u64;
        if start_position >= file_len {
            return Ok((Vec::new(), 0, bytes_per_sample));
        }

        file.seek(SeekFrom::Start(start_position))
            .with_context(|| format!("定位文件偏移失败: {}", file_path.display()))?;

        let remaining = file_len - start_position;
        let bytes_to_read = remaining.min((samples_to_read * step) as u64) as usize;
        if bytes_to_read == 0 {
            return Ok((Vec::new(), 0, bytes_per_sample));
        }

        let mut buffer = vec![0u8; bytes_to_read];
        file.read_exact(&mut buffer)
            .with_context(|| format!("读取声波文件失败: {}", file_path.display()))?;

        let actual_samples = bytes_to_read / step;
        Ok((buffer, actual_samples, bytes_per_sample))
    }
}

fn convert_to_voltage(sample: f32, coef: f32, range: f32) -> f32 {
    if coef == 0.0 {
        return sample;
    }
    sample / coef * range
}
